DynamicQuant

将 FP32 输入张量按给定的 scale 和 zero point(zp)动态量化为 INT8 输出张量。 支持按整张量量化或按指定轴分段量化(per-axis dynamic quantization)。

\[q_i = \mathrm{clip}\left( \mathrm{round}\left( \frac{x_i}{scale} + zp \right), q_{min}, q_{max} \right)\]

其中:

  • \(x_i\) 为输入浮点值

  • \(scale\) 为量化比例因子

  • \(zp\) 为零点(zero point)

  • \(q_{min} = -128\)

  • \(q_{max} = 127\)

当输入为 \(+\infty\)\(-\infty\) 时,输出分别饱和到最大或最小量化值。

输入:
  • real_values - 输入 FP32 数据地址

  • element_num - 输入元素总数

  • scale - 量化 scale 数组地址

  • zp - 量化 zero point 数组地址

  • segment_num - 分段数量(用于按轴量化)

  • axis_num - 量化轴标识
    • 0:整张量量化(per-tensor)

    • !=0:按轴分段量化(per-axis)

输出:
  • quant_values - 输出 INT8 量化结果地址

支持平台:

FT78NE MT7004

备注

  • 当前算子仅支持 FP32Fp16 → INT8 的动态量化

  • axis_num = 0 时,仅使用 scale[0]zp[0] 进行整张量量化

  • axis_num != 0 时,输入按 segment_num 进行分段,每段使用对应的 scale[i]zp[i]

  • 分段大小通过 UP_DIV(element_num, segment_num) 计算,最后一段自动处理剩余元素

  • 量化结果会被限制在 [-128, 127] 范围内

私有存储版本:

void fp_QuantData_p(float *real_values, int8_t *quant_values, int element_num, float *scale, int *zp, int segment_num, int axis_num)
void hp_QuantData_p(half *real_values, half *quant_values, int element_num, half *scale, int *zp, int segment_num, int axis_num)

C调用示例:

 1#include <stdio.h>
 2#include <quant.h>
 3
 4int main(int argc, char* argv[]) {
 5    float *input = (float *)0x10000000;      // FP32 输入
 6    int8_t *output = (int8_t *)0x10004000;   // INT8 输出
 7    float scale[4] = {0.1f, 0.12f, 0.11f, 0.09f};
 8    int zp[4] = {0, 0, 0, 0};
 9    int element_num = 1024;
10    int segment_num = 4;
11    int axis_num = 1;
12
13    fp_QuantData_p(input, output, element_num,
14              scale, zp, segment_num, axis_num);
15
16    return 0;
17}

共享存储版本:

void fp_QuantData_s(float *real_values, int8_t *quant_values, int element_num, float *scale, int *zp, int segment_num, int axis_num, int core_mask)
void hp_QuantData_s(half *real_values, half *quant_values, int element_num, half *scale, int *zp, int segment_num, int axis_num, int core_mask)

C调用示例:

 1#include <stdio.h>
 2#include <quant.h>
 3
 4int main(int argc, char* argv[]) {
 5    float *input = (float *)0x10000000;      // FP32 输入
 6    int8_t *output = (int8_t *)0x10004000;   // INT8 输出
 7    float scale[4] = {0.1f, 0.12f, 0.11f, 0.09f};
 8    int zp[4] = {0, 0, 0, 0};
 9    int element_num = 1024;
10    int segment_num = 4;
11    int axis_num = 1, core_mask = 0xff;
12
13    fp_QuantData_s(input, output, element_num,
14              scale, zp, segment_num, axis_num, core_mask);
15
16    return 0;
17}

实现说明:

  • axis_num == 0 时:

    • 对整个输入数组执行一次统一量化

    • 等价于 per-tensor quantization

  • axis_num != 0 时:

    • 输入数据按 segment_num 均分为多个分段

    • 每个分段使用独立的 scale[i]zp[i]

    • 等价于 per-axis dynamic quantization

  • 核心量化过程由 DoQuantizeFp32ToInt8 完成,包括:

    • 反 scale 计算

    • 四舍五入

    • 饱和裁剪

    • INF 特殊值处理